using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace net.notdot.Attercop
{
    public class FileHandler : IFileHandler
    {
        private Dictionary<Peer, SortedList<string, object>> PeerFiles = new Dictionary<Peer, SortedList<string, object>>();
        private Dictionary<string, SortedList<Peer, object>> FilePeers = new Dictionary<string, SortedList<Peer, object>>();
        private Dictionary<Peer, PeerConnection> Connections = new Dictionary<Peer, PeerConnection>();

        /// <summary>
        /// Adds a file to the FileHandler's list of files to retrieve.
        /// </summary>
        /// <remarks>
        /// If the peer specified is new, a connection is established to that peer.
        /// </remarks>
        public void AddFile(ClientInstance c, string file, Peer p)
        {
            //Add it to the peer's file listing
            if (!PeerFiles.ContainsKey(p))
            {
                PeerFiles.Add(p, new SortedList<string, object>());
                Connections.Add(p, new PeerConnection(c, p));
            }
            if (PeerFiles[p].ContainsKey(file))
                return;
            PeerFiles[p].Add(file, null);

            //Add it to the file's peer listing
            if (!FilePeers.ContainsKey(file))
                FilePeers.Add(file, new SortedList<Peer, object>());
            FilePeers[file].Add(p, null);
        }

        /// <summary>
        /// Removes a file from the FileHandler's list of files to retrieve.
        /// </summary>
        /// <remarks>
        /// If the specified file is the last one associated with a particular peer,
        /// the connection with that peer is terminated.
        /// </remarks>
        public void RemoveFile(string file)
        {
            if (!FilePeers.ContainsKey(file))
                return;

            //Remove the file from all peer entries
            foreach (KeyValuePair<Peer, Object> kvp in FilePeers[file])
            {
                PeerFiles[kvp.Key].Remove(file);
                //If this is the last file for this peer, disconnect from them.
                if (PeerFiles[kvp.Key].Count == 0)
                {
                    Connections[kvp.Key].Close();
                    Connections.Remove(kvp.Key);
                    PeerFiles.Remove(kvp.Key);
                }
            }

            FilePeers.Remove(file);
        }
        
        /// <summary>
        /// Removes a peer from the list of peers we are retrieving files from, and disconnects from them.
        /// </summary>
        public void RemovePeer(Peer p)
        {
            if (!PeerFiles.ContainsKey(p))
                return;

            //Remove the peer from all file entries
            foreach (KeyValuePair<string, Object> kvp in PeerFiles[p])
                FilePeers[kvp.Key].Remove(p);

            Connections[p].Close();
            Connections.Remove(p);
            PeerFiles.Remove(p);
        }

        /// <summary>
        /// Retrieves a list of files we are fetching, and the associated peers for each.
        /// </summary>
        public Dictionary<string, SortedList<Peer, object>>.Enumerator Files
        {
            get
            {
                return FilePeers.GetEnumerator();
            }
        }

        #region IFileHandler Members

        public string GetDesiredFile(PeerConnection conn)
        {
            return PeerFiles[conn.Peer].Keys[0];
        }

        public void HandleIncomingConnection(PeerConnection conn) 
        {            
        }

        public void HandleIncomingDisconnection(PeerConnection conn) 
        {
        }

        public void HandleOutgoingConnection(PeerConnection conn) 
        {            
        }

        public void HandleOutgoingDisconnection(PeerConnection conn)
        {
        }

        public void HandleQueueNotification(PeerConnection conn, QueueNotificationMessage m)
        {
        }

        public void HandleIncomingFile(PeerConnection conn, IncomingFileMessage m, Stream s)
        {
            //TODO: Implement
        }

        public void HandleFileRequest(PeerConnection conn, SendMeMessage m)
        {
            //TODO: Implement
        }

        #endregion
    }
}
